﻿using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using xEngine.Actors;
using xEngine.Actors.Terrain;

namespace xEngine.Rendering.Effects
{
    class FXTerrain : Effect, XEffect
    {
        private static readonly int LAYERS = 4;   // MUST match the shader value!
        private static readonly string ALPHAMAP = "texture" + LAYERS;
        private static readonly int CURSOR_LAYER = 15;
        private static readonly string CURSOR = "texture" + CURSOR_LAYER;

        #region Member Variables

        private Terrain _terrain;

        #endregion

        #region Properties

        #endregion

        #region Constructors

        public FXTerrain(Terrain terrain) : base(RenderManager.EmbeddedContent.Load<Effect>("sh_terrain_simple"))
        {
            _terrain = terrain;
        }

        #endregion

        #region Functions

        public void Apply(Camera camera)
        {
            Parameters["View"].SetValue(camera.View);
            Parameters["Projection"].SetValue(camera.Projection);
            Parameters["World"].SetValue(_terrain.Transformation.Matrix);
            Parameters["Rotation"].SetValue(_terrain.Transformation.RotationM);

            Vector2[] offsets = new Vector2[_terrain.Layers.Count];
            Vector2[] scales = new Vector2[_terrain.Layers.Count];
            Vector4[] colors = new Vector4[_terrain.Layers.Count];

            for (int i = 0; i < _terrain.Layers.Count; i++)
            {
                Parameters["texture" + i].SetValue(_terrain.Layers[i].Texture);
                offsets[i] = _terrain.Layers[i].Offset;
                scales[i] = _terrain.Layers[i].Scale;
                colors[i] = _terrain.Layers[i].Color;
            }

            Parameters["Offset"].SetValue(offsets);
            Parameters["Scale"].SetValue(scales);
            Parameters["Color"].SetValue(colors);

            Parameters["TerrainOffset"].SetValue(new Vector2((_terrain.HeightMap.Width - 1) / 2, (_terrain.HeightMap.Height - 1) / 2));

            Parameters[ALPHAMAP].SetValue(_terrain.AlphaMap);

            Parameters["LightDirection"].SetValue(new Vector3(-1, -1, -1));
            Parameters["AmbientIntensity"].SetValue(0.2f);
            Parameters["AmbientColor"].SetValue(Vector3.One);
            Parameters["DiffuseIntensity"].SetValue(1.0f);
            Parameters["DiffuseColor"].SetValue(Vector3.One);

            Parameters["ShowCursor"].SetValue(_terrain.TerrainCursor.Show);
            Parameters["CursorPosition"].SetValue(_terrain.TerrainCursor.Position);
            Parameters["CursorScale"].SetValue(_terrain.TerrainCursor.Scale);
            Parameters["CursorColor"].SetValue(_terrain.TerrainCursor.Color);
            Parameters[CURSOR].SetValue(_terrain.TerrainCursor.Texture);

            CurrentTechnique.Passes[0].Apply();

            for (int i = 0; i < _terrain.Layers.Count; i++)
                _terrain.GraphicsDevice.SamplerStates[i] = new SamplerState() { Filter = TextureFilter.Anisotropic, MaxAnisotropy = 16 };

            _terrain.GraphicsDevice.SamplerStates[CURSOR_LAYER] = new SamplerState()
            {
                Filter = TextureFilter.Point,
                AddressU = TextureAddressMode.Clamp,
                AddressV = TextureAddressMode.Clamp
            };
        }

        #endregion
    }
}
